#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QLabel, 
                            QHBoxLayout, QPushButton, QSizePolicy, QMenu)
from PyQt6.QtCore import Qt, QSize
from PyQt6.QtGui import QPixmap, QKeyEvent, QAction
import zipfile
from PIL import Image
from io import BytesIO
from utils import ComicUtils

class ComicViewer(QMainWindow):
    """漫画阅读窗口类"""
    
    def __init__(self, file_path, image_files):
        super().__init__()
        
        # 设置窗口属性
        self.setWindowTitle("漫画阅读")
        self.setMinimumSize(800, 600)
        
        # 初始化变量
        self.file_path = file_path
        self.image_files = image_files
        self.current_index = 0
        self.is_fullscreen = False
        self.scale_factor = 1.0
        self.original_pixmap = None
        self.fit_to_screen = False  # 适应屏幕模式
        
        # 初始化UI
        self.init_ui()
        
        # 初始化右键菜单
        self.init_context_menu()
        
        # 加载第一张图片
        self.load_current_image()
        
    def init_ui(self):
        """初始化用户界面"""
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(0, 0, 0, 0)  # 移除边距以最大化显示区域
        
        # 创建图片显示区域
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.image_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        self.image_label.setStyleSheet("background-color: #1A1A1A;")
        
        main_layout.addWidget(self.image_label)
        
        # 创建底部控制栏容器
        self.control_widget = QWidget()
        control_layout = QHBoxLayout(self.control_widget)
        control_layout.setContentsMargins(10, 5, 10, 5)
        
        # 添加返回按钮
        self.back_btn = QPushButton("返回")
        self.back_btn.setToolTip("返回到漫画列表")
        self.back_btn.clicked.connect(self.close)
        control_layout.addWidget(self.back_btn)
        
        # 添加页码显示
        self.page_label = QLabel()
        self.page_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.page_label.setStyleSheet("font-size: 14px; font-weight: bold;")
        control_layout.addWidget(self.page_label, 1)  # 1表示拉伸因子
        
        # 添加上一页/下一页按钮
        self.prev_btn = QPushButton("上一页")
        self.prev_btn.setToolTip("查看上一页 (左方向键)")
        self.prev_btn.clicked.connect(self.prev_image)
        control_layout.addWidget(self.prev_btn)
        
        self.next_btn = QPushButton("下一页")
        self.next_btn.setToolTip("查看下一页 (右方向键)")
        self.next_btn.clicked.connect(self.next_image)
        control_layout.addWidget(self.next_btn)
        
        # 将控制栏容器添加到主布局
        main_layout.addWidget(self.control_widget)
        
        # 设置状态栏
        self.statusBar().showMessage("点击图片左侧区域查看上一页，右侧区域查看下一页，中间区域不翻页，按Enter全屏，按ESC键返回，上下键缩放图片")
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QLabel, 
                            QHBoxLayout, QPushButton, QSizePolicy, QMenu)
from PyQt6.QtCore import Qt, QSize
from PyQt6.QtGui import QPixmap, QKeyEvent, QAction
import zipfile
from PIL import Image
from io import BytesIO
from utils import ComicUtils

class ComicViewer(QMainWindow):
    """漫画阅读窗口类"""
    
    def __init__(self, file_path, image_files):
        super().__init__()
        
        # 设置窗口属性
        self.setWindowTitle("漫画阅读")
        self.setMinimumSize(800, 600)
        
        # 初始化变量
        self.file_path = file_path
        self.image_files = image_files
        self.current_index = 0
        self.is_fullscreen = False
        self.scale_factor = 1.0
        self.original_pixmap = None
        self.fit_to_screen = False  # 适应屏幕模式
        
        # 初始化UI
        self.init_ui()
        
        # 初始化右键菜单
        self.init_context_menu()
        
        # 加载第一张图片
        self.load_current_image()
        
    def init_ui(self):
        """初始化用户界面"""
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(0, 0, 0, 0)  # 移除边距以最大化显示区域
        
        # 创建图片显示区域
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.image_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        self.image_label.setStyleSheet("background-color: #1A1A1A;")
        
        main_layout.addWidget(self.image_label)
        
        # 创建底部控制栏容器
        self.control_widget = QWidget()
        control_layout = QHBoxLayout(self.control_widget)
        control_layout.setContentsMargins(10, 5, 10, 5)
        
        # 添加返回按钮
        self.back_btn = QPushButton("返回")
        self.back_btn.setToolTip("返回到漫画列表")
        self.back_btn.clicked.connect(self.close)
        control_layout.addWidget(self.back_btn)
        
        # 添加页码显示
        self.page_label = QLabel()
        self.page_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.page_label.setStyleSheet("font-size: 14px; font-weight: bold;")
        control_layout.addWidget(self.page_label, 1)  # 1表示拉伸因子
        
        # 添加上一页/下一页按钮
        self.prev_btn = QPushButton("上一页")
        self.prev_btn.setToolTip("查看上一页 (左方向键)")
        self.prev_btn.clicked.connect(self.prev_image)
        control_layout.addWidget(self.prev_btn)
        
        self.next_btn = QPushButton("下一页")
        self.next_btn.setToolTip("查看下一页 (右方向键)")
        self.next_btn.clicked.connect(self.next_image)
        control_layout.addWidget(self.next_btn)
        
        # 将控制栏容器添加到主布局
        main_layout.addWidget(self.control_widget)
        
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QLabel, 
                            QHBoxLayout, QPushButton, QSizePolicy, QMenu)
from PyQt6.QtCore import Qt, QSize
from PyQt6.QtGui import QPixmap, QKeyEvent, QAction
import zipfile
from PIL import Image
from io import BytesIO
from utils import ComicUtils

class ComicViewer(QMainWindow):
    """漫画阅读窗口类"""
    
    def __init__(self, file_path, image_files):
        super().__init__()
        
        # 设置窗口属性
        self.setWindowTitle("漫画阅读")
        self.setMinimumSize(800, 600)
        
        # 初始化变量
        self.file_path = file_path
        self.image_files = image_files
        self.current_index = 0
        self.is_fullscreen = False
        self.scale_factor = 1.0
        self.original_pixmap = None
        self.fit_to_screen = False  # 适应屏幕模式
        
        # 初始化UI
        self.init_ui()
        
        # 初始化右键菜单
        self.init_context_menu()
        
        # 加载第一张图片
        self.load_current_image()
        
    def init_ui(self):
        """初始化用户界面"""
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(0, 0, 0, 0)  # 移除边距以最大化显示区域
        
        # 创建图片显示区域
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.image_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        self.image_label.setStyleSheet("background-color: #1A1A1A;")
        
        main_layout.addWidget(self.image_label)
        
        # 创建底部控制栏容器
        self.control_widget = QWidget()
        control_layout = QHBoxLayout(self.control_widget)
        control_layout.setContentsMargins(10, 5, 10, 5)
        
        # 添加返回按钮
        self.back_btn = QPushButton("返回")
        self.back_btn.setToolTip("返回到漫画列表")
        self.back_btn.clicked.connect(self.close)
        control_layout.addWidget(self.back_btn)
        
        # 添加页码显示
        self.page_label = QLabel()
        self.page_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.page_label.setStyleSheet("font-size: 14px; font-weight: bold;")
        control_layout.addWidget(self.page_label, 1)  # 1表示拉伸因子
        
        # 添加上一页/下一页按钮
        self.prev_btn = QPushButton("上一页")
        self.prev_btn.setToolTip("查看上一页 (左方向键)")
        self.prev_btn.clicked.connect(self.prev_image)
        control_layout.addWidget(self.prev_btn)
        
        self.next_btn = QPushButton("下一页")
        self.next_btn.setToolTip("查看下一页 (右方向键)")
        self.next_btn.clicked.connect(self.next_image)
        control_layout.addWidget(self.next_btn)
        
        # 将控制栏容器添加到主布局
        main_layout.addWidget(self.control_widget)
        
        # 设置状态栏
        self.statusBar().showMessage("点击图片左侧区域查看上一页，右侧区域查看下一页，按Enter全屏，按ESC键返回，上下键缩放图片")
        
        # 设置窗口标志，使其可以全屏显示
        self.setWindowState(Qt.WindowState.WindowMaximized)
        
        # 设置焦点策略，确保能接收键盘事件
        self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
        self.image_label.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
        
    def init_context_menu(self):
        """初始化右键菜单"""
        # 创建右键菜单
        self.context_menu = QMenu(self)
        
        # 创建适应屏幕动作
        self.fit_screen_action = QAction("适应屏幕", self)
        self.fit_screen_action.setCheckable(True)
        self.fit_screen_action.setChecked(self.fit_to_screen)
        self.fit_screen_action.triggered.connect(self.toggle_fit_to_screen)
        
        # 创建全屏动作
        self.fullscreen_action = QAction("全屏显示", self)
        self.fullscreen_action.setCheckable(True)
        self.fullscreen_action.setChecked(self.is_fullscreen)
        self.fullscreen_action.triggered.connect(self.toggle_fullscreen)
        
        # 创建原始大小动作
        self.original_size_action = QAction("原始大小", self)
        self.original_size_action.triggered.connect(self.show_original_size)
        
        # 添加动作到菜单
        self.context_menu.addAction(self.fit_screen_action)
        self.context_menu.addAction(self.fullscreen_action)
        self.context_menu.addAction(self.original_size_action)
        
        # 设置图片标签的上下文菜单策略
        self.image_label.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.image_label.customContextMenuRequested.connect(self.show_context_menu)
    
    def show_context_menu(self, position):
        """显示右键菜单"""
        # 更新全屏菜单项的状态
        self.fullscreen_action.setChecked(self.is_fullscreen)
        
        # 将位置转换为全局坐标
        global_pos = self.image_label.mapToGlobal(position)
        # 显示菜单
        self.context_menu.exec(global_pos)
    
    def toggle_fit_to_screen(self):
        """切换适应屏幕模式"""
        self.fit_to_screen = not self.fit_to_screen
        self.fit_screen_action.setChecked(self.fit_to_screen)
        
        # 如果启用适应屏幕，则重置缩放因子
        if self.fit_to_screen:
            self.scale_factor = 1.0
        
        # 重新显示当前图片以应用新的显示模式
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏信息
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        mode_text = "适应屏幕模式" if self.fit_to_screen else "正常模式"
        self.statusBar().showMessage(f"正在查看: {file_name} - {mode_text}")
    
    def show_original_size(self):
        """显示原始大小"""
        # 禁用适应屏幕模式
        self.fit_to_screen = False
        self.fit_screen_action.setChecked(False)
        
        # 设置缩放因子为1.0（原始大小）
        self.scale_factor = 1.0
        
        # 重新显示当前图片
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏信息
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        self.statusBar().showMessage(f"正在查看: {file_name} - 原始大小")
        
    def load_current_image(self):
        """加载当前索引的图片"""
        if not self.image_files or self.current_index < 0 or self.current_index >= len(self.image_files):
            return
        
        # 更新按钮状态
        self.prev_btn.setEnabled(self.current_index > 0)
        self.next_btn.setEnabled(self.current_index < len(self.image_files) - 1)
        
        # 检查ZIP文件是否有效
        if not ComicUtils.is_valid_zip(self.file_path):
            ComicUtils.show_error_message(self, "错误", "无效的ZIP文件")
            self.statusBar().showMessage("错误: 无效的ZIP文件")
            self.image_label.setText("无法加载图片: 无效的ZIP文件")
            return
            
        try:
            with zipfile.ZipFile(self.file_path, 'r') as zip_ref:
                current_image = self.image_files[self.current_index]
                
                # 更新窗口标题显示当前文件名
                file_name = current_image.split('/')[-1] if '/' in current_image else current_image
                self.setWindowTitle(f"漫画阅读 - {file_name}")
                
                # 检查文件是否存在于ZIP中
                if current_image not in zip_ref.namelist():
                    self.statusBar().showMessage(f"错误: 文件 {current_image} 不存在于ZIP中")
                    self.image_label.setText(f"文件不存在: {current_image}")
                    return
                
                # 检查是否为图片文件
                if not ComicUtils.is_image_file(current_image):
                    self.statusBar().showMessage(f"错误: {current_image} 不是图片文件")
                    self.image_label.setText(f"不是图片文件: {current_image}")
                    return
                
                with zip_ref.open(current_image) as img_file:
                    img_data = img_file.read()
                    img = Image.open(BytesIO(img_data))
                    
                    # 转换PIL图像为QPixmap
                    # 首先转换为RGB模式（如果不是的话）
                    if img.mode != 'RGB':
                        img = img.convert('RGB')
                    
                    # 将PIL图像转换为字节数据
                    img_bytes = BytesIO()
                    img.save(img_bytes, format='PNG')
                    img_bytes.seek(0)
                    
                    # 从字节数据创建QPixmap
                    qimg = QPixmap()
                    qimg.loadFromData(img_bytes.getvalue())
                    
                    # 调整图片大小以适应窗口
                    self.display_image(qimg)
                    
                    # 重置缩放因子（除非在适应屏幕模式下）
                    if not self.fit_to_screen:
                        self.scale_factor = 1.0
                    
                    # 更新页码显示
                    self.page_label.setText(f"第 {self.current_index + 1} 页 / 共 {len(self.image_files)} 页")
                    
                    # 更新状态栏
                    mode_text = "适应屏幕模式" if self.fit_to_screen else "正常模式"
                    self.statusBar().showMessage(f"正在查看: {file_name} - {mode_text}")
        except zipfile.BadZipFile:
            ComicUtils.show_error_message(self, "错误", "无效的ZIP文件")
            self.statusBar().showMessage("错误: 无效的ZIP文件")
            self.image_label.setText("无法加载图片: 无效的ZIP文件")
        except Exception as e:
            ComicUtils.show_error_message(self, "错误", f"加载图片出错: {str(e)}")
            self.statusBar().showMessage(f"加载图片出错: {str(e)}")
            self.image_label.setText("无法加载图片")
    
    def display_image(self, pixmap):
        """显示图片并调整大小"""
        # 保存原始图片
        self.original_pixmap = pixmap
        
        # 获取图片标签的大小
        label_size = self.image_label.size()
        
        # 获取图片原始大小
        img_width = pixmap.width()
        img_height = pixmap.height()
        
        if self.fit_to_screen:
            # 适应屏幕模式：根据显示器分辨率智能缩放
            # 获取屏幕尺寸
            screen = self.screen()
            screen_size = screen.availableGeometry().size()
            
            # 计算缩放比例，使图片适应屏幕但不拉伸变形
            width_ratio = screen_size.width() / img_width
            height_ratio = screen_size.height() / img_height
            
            # 选择较小的比例以确保图片完全显示且不变形
            fit_scale_ratio = min(width_ratio, height_ratio)
            
            # 限制最大缩放比例，避免图片过大
            fit_scale_ratio = min(fit_scale_ratio, 3.0)
            
            final_scale_ratio = fit_scale_ratio
        else:
            # 正常模式：根据窗口大小调整
            # 计算基础缩放比例
            width_ratio = label_size.width() / img_width
            height_ratio = label_size.height() / img_height
            
            # 选择较小的比例以确保图片完全显示在窗口内
            base_scale_ratio = min(width_ratio, height_ratio)
            
            # 如果图片比窗口小，则不放大（除非用户手动缩放）
            if base_scale_ratio > 1.0 and self.scale_factor == 1.0:
                base_scale_ratio = 1.0
            
            # 应用用户缩放因子
            final_scale_ratio = base_scale_ratio * self.scale_factor
            
        # 缩放图片
        scaled_pixmap = pixmap.scaled(
            int(img_width * final_scale_ratio),
            int(img_height * final_scale_ratio),
            Qt.AspectRatioMode.KeepAspectRatio,
            Qt.TransformationMode.SmoothTransformation
        )
        
        # 设置图片
        self.image_label.setPixmap(scaled_pixmap)
    
    def prev_image(self):
        """显示上一张图片"""
        if self.current_index > 0:
            self.current_index -= 1
            self.load_current_image()
    
    def next_image(self):
        """显示下一张图片"""
        if self.current_index < len(self.image_files) - 1:
            self.current_index += 1
            self.load_current_image()
    
    def mousePressEvent(self, event):
        """处理鼠标点击事件"""
        # 获取窗口宽度
        width = self.width()
        
        # 获取鼠标点击位置
        x = event.position().x()
        
        # 定义中间区域的宽度（窗口宽度的30%）
        middle_width = width * 0.3
        left_boundary = (width - middle_width) / 2
        right_boundary = left_boundary + middle_width
        
        # 如果点击在左侧区域，显示上一页
        if x < left_boundary:
            self.prev_image()
        # 如果点击在右侧区域，显示下一页
        elif x > right_boundary:
            self.next_image()
        # 点击中间区域不做任何操作
        else:
            pass  # 中间区域不翻页
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QLabel, 
                            QHBoxLayout, QPushButton, QSizePolicy, QMenu)
from PyQt6.QtCore import Qt, QSize
from PyQt6.QtGui import QPixmap, QKeyEvent, QAction
import zipfile
from PIL import Image
from io import BytesIO
from utils import ComicUtils

class ComicViewer(QMainWindow):
    """漫画阅读窗口类"""
    
    def __init__(self, file_path, image_files):
        super().__init__()
        
        # 设置窗口属性
        self.setWindowTitle("漫画阅读")
        self.setMinimumSize(800, 600)
        
        # 初始化变量
        self.file_path = file_path
        self.image_files = image_files
        self.current_index = 0
        self.is_fullscreen = False
        self.scale_factor = 1.0
        self.original_pixmap = None
        self.fit_to_screen = False  # 适应屏幕模式
        
        # 初始化UI
        self.init_ui()
        
        # 初始化右键菜单
        self.init_context_menu()
        
        # 加载第一张图片
        self.load_current_image()
        
    def init_ui(self):
        """初始化用户界面"""
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(0, 0, 0, 0)  # 移除边距以最大化显示区域
        
        # 创建图片显示区域
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.image_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        self.image_label.setStyleSheet("background-color: #1A1A1A;")
        
        main_layout.addWidget(self.image_label)
        
        # 创建底部控制栏容器
        self.control_widget = QWidget()
        control_layout = QHBoxLayout(self.control_widget)
        control_layout.setContentsMargins(10, 5, 10, 5)
        
        # 添加返回按钮
        self.back_btn = QPushButton("返回")
        self.back_btn.setToolTip("返回到漫画列表")
        self.back_btn.clicked.connect(self.close)
        control_layout.addWidget(self.back_btn)
        
        # 添加页码显示
        self.page_label = QLabel()
        self.page_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.page_label.setStyleSheet("font-size: 14px; font-weight: bold;")
        control_layout.addWidget(self.page_label, 1)  # 1表示拉伸因子
        
        # 添加上一页/下一页按钮
        self.prev_btn = QPushButton("上一页")
        self.prev_btn.setToolTip("查看上一页 (左方向键)")
        self.prev_btn.clicked.connect(self.prev_image)
        control_layout.addWidget(self.prev_btn)
        
        self.next_btn = QPushButton("下一页")
        self.next_btn.setToolTip("查看下一页 (右方向键)")
        self.next_btn.clicked.connect(self.next_image)
        control_layout.addWidget(self.next_btn)
        
        # 将控制栏容器添加到主布局
        main_layout.addWidget(self.control_widget)
        
        # 设置状态栏
        self.statusBar().showMessage("点击图片左侧区域查看上一页，右侧区域查看下一页，按Enter全屏，按ESC键返回，上下键缩放图片")
        
        # 设置窗口标志，使其可以全屏显示
        self.setWindowState(Qt.WindowState.WindowMaximized)
        
        # 设置焦点策略，确保能接收键盘事件
        self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
        self.image_label.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
        
    def init_context_menu(self):
        """初始化右键菜单"""
        # 创建右键菜单
        self.context_menu = QMenu(self)
        
        # 创建适应屏幕动作
        self.fit_screen_action = QAction("适应屏幕", self)
        self.fit_screen_action.setCheckable(True)
        self.fit_screen_action.setChecked(self.fit_to_screen)
        self.fit_screen_action.triggered.connect(self.toggle_fit_to_screen)
        
        # 创建全屏动作
        self.fullscreen_action = QAction("全屏显示", self)
        self.fullscreen_action.setCheckable(True)
        self.fullscreen_action.setChecked(self.is_fullscreen)
        self.fullscreen_action.triggered.connect(self.toggle_fullscreen)
        
        # 创建原始大小动作
        self.original_size_action = QAction("原始大小", self)
        self.original_size_action.triggered.connect(self.show_original_size)
        
        # 添加动作到菜单
        self.context_menu.addAction(self.fit_screen_action)
        self.context_menu.addAction(self.fullscreen_action)
        self.context_menu.addAction(self.original_size_action)
        
        # 设置图片标签的上下文菜单策略
        self.image_label.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.image_label.customContextMenuRequested.connect(self.show_context_menu)
    
    def show_context_menu(self, position):
        """显示右键菜单"""
        # 更新全屏菜单项的状态
        self.fullscreen_action.setChecked(self.is_fullscreen)
        
        # 将位置转换为全局坐标
        global_pos = self.image_label.mapToGlobal(position)
        # 显示菜单
        self.context_menu.exec(global_pos)
    
    def toggle_fit_to_screen(self):
        """切换适应屏幕模式"""
        self.fit_to_screen = not self.fit_to_screen
        self.fit_screen_action.setChecked(self.fit_to_screen)
        
        # 如果启用适应屏幕，则重置缩放因子
        if self.fit_to_screen:
            self.scale_factor = 1.0
        
        # 重新显示当前图片以应用新的显示模式
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏信息
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        mode_text = "适应屏幕模式" if self.fit_to_screen else "正常模式"
        self.statusBar().showMessage(f"正在查看: {file_name} - {mode_text}")
    
    def show_original_size(self):
        """显示原始大小"""
        # 禁用适应屏幕模式
        self.fit_to_screen = False
        self.fit_screen_action.setChecked(False)
        
        # 设置缩放因子为1.0（原始大小）
        self.scale_factor = 1.0
        
        # 重新显示当前图片
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏信息
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        self.statusBar().showMessage(f"正在查看: {file_name} - 原始大小")
        
    def load_current_image(self):
        """加载当前索引的图片"""
        if not self.image_files or self.current_index < 0 or self.current_index >= len(self.image_files):
            return
        
        # 更新按钮状态
        self.prev_btn.setEnabled(self.current_index > 0)
        self.next_btn.setEnabled(self.current_index < len(self.image_files) - 1)
        
        # 检查ZIP文件是否有效
        if not ComicUtils.is_valid_zip(self.file_path):
            ComicUtils.show_error_message(self, "错误", "无效的ZIP文件")
            self.statusBar().showMessage("错误: 无效的ZIP文件")
            self.image_label.setText("无法加载图片: 无效的ZIP文件")
            return
            
        try:
            with zipfile.ZipFile(self.file_path, 'r') as zip_ref:
                current_image = self.image_files[self.current_index]
                
                # 更新窗口标题显示当前文件名
                file_name = current_image.split('/')[-1] if '/' in current_image else current_image
                self.setWindowTitle(f"漫画阅读 - {file_name}")
                
                # 检查文件是否存在于ZIP中
                if current_image not in zip_ref.namelist():
                    self.statusBar().showMessage(f"错误: 文件 {current_image} 不存在于ZIP中")
                    self.image_label.setText(f"文件不存在: {current_image}")
                    return
                
                # 检查是否为图片文件
                if not ComicUtils.is_image_file(current_image):
                    self.statusBar().showMessage(f"错误: {current_image} 不是图片文件")
                    self.image_label.setText(f"不是图片文件: {current_image}")
                    return
                
                with zip_ref.open(current_image) as img_file:
                    img_data = img_file.read()
                    img = Image.open(BytesIO(img_data))
                    
                    # 转换PIL图像为QPixmap
                    # 首先转换为RGB模式（如果不是的话）
                    if img.mode != 'RGB':
                        img = img.convert('RGB')
                    
                    # 将PIL图像转换为字节数据
                    img_bytes = BytesIO()
                    img.save(img_bytes, format='PNG')
                    img_bytes.seek(0)
                    
                    # 从字节数据创建QPixmap
                    qimg = QPixmap()
                    qimg.loadFromData(img_bytes.getvalue())
                    
                    # 调整图片大小以适应窗口
                    self.display_image(qimg)
                    
                    # 重置缩放因子（除非在适应屏幕模式下）
                    if not self.fit_to_screen:
                        self.scale_factor = 1.0
                    
                    # 更新页码显示
                    self.page_label.setText(f"第 {self.current_index + 1} 页 / 共 {len(self.image_files)} 页")
                    
                    # 更新状态栏
                    mode_text = "适应屏幕模式" if self.fit_to_screen else "正常模式"
                    self.statusBar().showMessage(f"正在查看: {file_name} - {mode_text}")
        except zipfile.BadZipFile:
            ComicUtils.show_error_message(self, "错误", "无效的ZIP文件")
            self.statusBar().showMessage("错误: 无效的ZIP文件")
            self.image_label.setText("无法加载图片: 无效的ZIP文件")
        except Exception as e:
            ComicUtils.show_error_message(self, "错误", f"加载图片出错: {str(e)}")
            self.statusBar().showMessage(f"加载图片出错: {str(e)}")
            self.image_label.setText("无法加载图片")
    
    def display_image(self, pixmap):
        """显示图片并调整大小"""
        # 保存原始图片
        self.original_pixmap = pixmap
        
        # 获取图片标签的大小
        label_size = self.image_label.size()
        
        # 获取图片原始大小
        img_width = pixmap.width()
        img_height = pixmap.height()
        
        if self.fit_to_screen:
            # 适应屏幕模式：根据显示器分辨率智能缩放
            # 获取屏幕尺寸
            screen = self.screen()
            screen_size = screen.availableGeometry().size()
            
            # 计算缩放比例，使图片适应屏幕但不拉伸变形
            width_ratio = screen_size.width() / img_width
            height_ratio = screen_size.height() / img_height
            
            # 选择较小的比例以确保图片完全显示且不变形
            fit_scale_ratio = min(width_ratio, height_ratio)
            
            # 限制最大缩放比例，避免图片过大
            fit_scale_ratio = min(fit_scale_ratio, 3.0)
            
            final_scale_ratio = fit_scale_ratio
        else:
            # 正常模式：根据窗口大小调整
            # 计算基础缩放比例
            width_ratio = label_size.width() / img_width
            height_ratio = label_size.height() / img_height
            
            # 选择较小的比例以确保图片完全显示在窗口内
            base_scale_ratio = min(width_ratio, height_ratio)
            
            # 如果图片比窗口小，则不放大（除非用户手动缩放）
            if base_scale_ratio > 1.0 and self.scale_factor == 1.0:
                base_scale_ratio = 1.0
            
            # 应用用户缩放因子
            final_scale_ratio = base_scale_ratio * self.scale_factor
            
        # 缩放图片
        scaled_pixmap = pixmap.scaled(
            int(img_width * final_scale_ratio),
            int(img_height * final_scale_ratio),
            Qt.AspectRatioMode.KeepAspectRatio,
            Qt.TransformationMode.SmoothTransformation
        )
        
        # 设置图片
        self.image_label.setPixmap(scaled_pixmap)
    
    def prev_image(self):
        """显示上一张图片"""
        if self.current_index > 0:
            self.current_index -= 1
            self.load_current_image()
    
    def next_image(self):
        """显示下一张图片"""
        if self.current_index < len(self.image_files) - 1:
            self.current_index += 1
            self.load_current_image()
    
#!/usr/bin/env python
# -*- coding: utf-8 -*-

from PyQt6.QtWidgets import (QMainWindow, QWidget, QVBoxLayout, QLabel, 
                            QHBoxLayout, QPushButton, QSizePolicy, QMenu)
from PyQt6.QtCore import Qt, QSize
from PyQt6.QtGui import QPixmap, QKeyEvent, QAction
import zipfile
from PIL import Image
from io import BytesIO
from utils import ComicUtils

class ComicViewer(QMainWindow):
    """漫画阅读窗口类"""
    
    def __init__(self, file_path, image_files):
        super().__init__()
        
        # 设置窗口属性
        self.setWindowTitle("漫画阅读")
        self.setMinimumSize(800, 600)
        
        # 初始化变量
        self.file_path = file_path
        self.image_files = image_files
        self.current_index = 0
        self.is_fullscreen = False
        self.scale_factor = 1.0
        self.original_pixmap = None
        self.fit_to_screen = False  # 适应屏幕模式
        
        # 初始化UI
        self.init_ui()
        
        # 初始化右键菜单
        self.init_context_menu()
        
        # 加载第一张图片
        self.load_current_image()
        
    def init_ui(self):
        """初始化用户界面"""
        # 创建中央部件
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # 创建主布局
        main_layout = QVBoxLayout(central_widget)
        main_layout.setContentsMargins(0, 0, 0, 0)  # 移除边距以最大化显示区域
        
        # 创建图片显示区域
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.image_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
        self.image_label.setStyleSheet("background-color: #1A1A1A;")
        
        main_layout.addWidget(self.image_label)
        
        # 创建底部控制栏容器
        self.control_widget = QWidget()
        control_layout = QHBoxLayout(self.control_widget)
        control_layout.setContentsMargins(10, 5, 10, 5)
        
        # 添加返回按钮
        self.back_btn = QPushButton("返回")
        self.back_btn.setToolTip("返回到漫画列表")
        self.back_btn.clicked.connect(self.close)
        control_layout.addWidget(self.back_btn)
        
        # 添加页码显示
        self.page_label = QLabel()
        self.page_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.page_label.setStyleSheet("font-size: 14px; font-weight: bold;")
        control_layout.addWidget(self.page_label, 1)  # 1表示拉伸因子
        
        # 添加上一页/下一页按钮
        self.prev_btn = QPushButton("上一页")
        self.prev_btn.setToolTip("查看上一页 (左方向键)")
        self.prev_btn.clicked.connect(self.prev_image)
        control_layout.addWidget(self.prev_btn)
        
        self.next_btn = QPushButton("下一页")
        self.next_btn.setToolTip("查看下一页 (右方向键)")
        self.next_btn.clicked.connect(self.next_image)
        control_layout.addWidget(self.next_btn)
        
        # 将控制栏容器添加到主布局
        main_layout.addWidget(self.control_widget)
        
        # 设置状态栏
        self.statusBar().showMessage("点击图片左侧区域查看上一页，右侧区域查看下一页，按Enter全屏，按ESC键返回，上下键缩放图片")
        
        # 设置窗口标志，使其可以全屏显示
        self.setWindowState(Qt.WindowState.WindowMaximized)
        
        # 设置焦点策略，确保能接收键盘事件
        self.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
        self.image_label.setFocusPolicy(Qt.FocusPolicy.StrongFocus)
        
    def init_context_menu(self):
        """初始化右键菜单"""
        # 创建右键菜单
        self.context_menu = QMenu(self)
        
        # 创建适应屏幕动作
        self.fit_screen_action = QAction("适应屏幕", self)
        self.fit_screen_action.setCheckable(True)
        self.fit_screen_action.setChecked(self.fit_to_screen)
        self.fit_screen_action.triggered.connect(self.toggle_fit_to_screen)
        
        # 创建全屏动作
        self.fullscreen_action = QAction("全屏显示", self)
        self.fullscreen_action.setCheckable(True)
        self.fullscreen_action.setChecked(self.is_fullscreen)
        self.fullscreen_action.triggered.connect(self.toggle_fullscreen)
        
        # 创建原始大小动作
        self.original_size_action = QAction("原始大小", self)
        self.original_size_action.triggered.connect(self.show_original_size)
        
        # 添加动作到菜单
        self.context_menu.addAction(self.fit_screen_action)
        self.context_menu.addAction(self.fullscreen_action)
        self.context_menu.addAction(self.original_size_action)
        
        # 设置图片标签的上下文菜单策略
        self.image_label.setContextMenuPolicy(Qt.ContextMenuPolicy.CustomContextMenu)
        self.image_label.customContextMenuRequested.connect(self.show_context_menu)
    
    def show_context_menu(self, position):
        """显示右键菜单"""
        # 更新全屏菜单项的状态
        self.fullscreen_action.setChecked(self.is_fullscreen)
        
        # 将位置转换为全局坐标
        global_pos = self.image_label.mapToGlobal(position)
        # 显示菜单
        self.context_menu.exec(global_pos)
    
    def toggle_fit_to_screen(self):
        """切换适应屏幕模式"""
        self.fit_to_screen = not self.fit_to_screen
        self.fit_screen_action.setChecked(self.fit_to_screen)
        
        # 如果启用适应屏幕，则重置缩放因子
        if self.fit_to_screen:
            self.scale_factor = 1.0
        
        # 重新显示当前图片以应用新的显示模式
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏信息
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        mode_text = "适应屏幕模式" if self.fit_to_screen else "正常模式"
        self.statusBar().showMessage(f"正在查看: {file_name} - {mode_text}")
    
    def show_original_size(self):
        """显示原始大小"""
        # 禁用适应屏幕模式
        self.fit_to_screen = False
        self.fit_screen_action.setChecked(False)
        
        # 设置缩放因子为1.0（原始大小）
        self.scale_factor = 1.0
        
        # 重新显示当前图片
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏信息
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        self.statusBar().showMessage(f"正在查看: {file_name} - 原始大小")
        
    def load_current_image(self):
        """加载当前索引的图片"""
        if not self.image_files or self.current_index < 0 or self.current_index >= len(self.image_files):
            return
        
        # 更新按钮状态
        self.prev_btn.setEnabled(self.current_index > 0)
        self.next_btn.setEnabled(self.current_index < len(self.image_files) - 1)
        
        # 检查ZIP文件是否有效
        if not ComicUtils.is_valid_zip(self.file_path):
            ComicUtils.show_error_message(self, "错误", "无效的ZIP文件")
            self.statusBar().showMessage("错误: 无效的ZIP文件")
            self.image_label.setText("无法加载图片: 无效的ZIP文件")
            return
            
        try:
            with zipfile.ZipFile(self.file_path, 'r') as zip_ref:
                current_image = self.image_files[self.current_index]
                
                # 更新窗口标题显示当前文件名
                file_name = current_image.split('/')[-1] if '/' in current_image else current_image
                self.setWindowTitle(f"漫画阅读 - {file_name}")
                
                # 检查文件是否存在于ZIP中
                if current_image not in zip_ref.namelist():
                    self.statusBar().showMessage(f"错误: 文件 {current_image} 不存在于ZIP中")
                    self.image_label.setText(f"文件不存在: {current_image}")
                    return
                
                # 检查是否为图片文件
                if not ComicUtils.is_image_file(current_image):
                    self.statusBar().showMessage(f"错误: {current_image} 不是图片文件")
                    self.image_label.setText(f"不是图片文件: {current_image}")
                    return
                
                with zip_ref.open(current_image) as img_file:
                    img_data = img_file.read()
                    img = Image.open(BytesIO(img_data))
                    
                    # 转换PIL图像为QPixmap
                    # 首先转换为RGB模式（如果不是的话）
                    if img.mode != 'RGB':
                        img = img.convert('RGB')
                    
                    # 将PIL图像转换为字节数据
                    img_bytes = BytesIO()
                    img.save(img_bytes, format='PNG')
                    img_bytes.seek(0)
                    
                    # 从字节数据创建QPixmap
                    qimg = QPixmap()
                    qimg.loadFromData(img_bytes.getvalue())
                    
                    # 调整图片大小以适应窗口
                    self.display_image(qimg)
                    
                    # 重置缩放因子（除非在适应屏幕模式下）
                    if not self.fit_to_screen:
                        self.scale_factor = 1.0
                    
                    # 更新页码显示
                    self.page_label.setText(f"第 {self.current_index + 1} 页 / 共 {len(self.image_files)} 页")
                    
                    # 更新状态栏
                    mode_text = "适应屏幕模式" if self.fit_to_screen else "正常模式"
                    self.statusBar().showMessage(f"正在查看: {file_name} - {mode_text}")
        except zipfile.BadZipFile:
            ComicUtils.show_error_message(self, "错误", "无效的ZIP文件")
            self.statusBar().showMessage("错误: 无效的ZIP文件")
            self.image_label.setText("无法加载图片: 无效的ZIP文件")
        except Exception as e:
            ComicUtils.show_error_message(self, "错误", f"加载图片出错: {str(e)}")
            self.statusBar().showMessage(f"加载图片出错: {str(e)}")
            self.image_label.setText("无法加载图片")
    
    def display_image(self, pixmap):
        """显示图片并调整大小"""
        # 保存原始图片
        self.original_pixmap = pixmap
        
        # 获取图片标签的大小
        label_size = self.image_label.size()
        
        # 获取图片原始大小
        img_width = pixmap.width()
        img_height = pixmap.height()
        
        if self.fit_to_screen:
            # 适应屏幕模式：根据显示器分辨率智能缩放
            # 获取屏幕尺寸
            screen = self.screen()
            screen_size = screen.availableGeometry().size()
            
            # 计算缩放比例，使图片适应屏幕但不拉伸变形
            width_ratio = screen_size.width() / img_width
            height_ratio = screen_size.height() / img_height
            
            # 选择较小的比例以确保图片完全显示且不变形
            fit_scale_ratio = min(width_ratio, height_ratio)
            
            # 限制最大缩放比例，避免图片过大
            fit_scale_ratio = min(fit_scale_ratio, 3.0)
            
            final_scale_ratio = fit_scale_ratio
        else:
            # 正常模式：根据窗口大小调整
            # 计算基础缩放比例
            width_ratio = label_size.width() / img_width
            height_ratio = label_size.height() / img_height
            
            # 选择较小的比例以确保图片完全显示在窗口内
            base_scale_ratio = min(width_ratio, height_ratio)
            
            # 如果图片比窗口小，则不放大（除非用户手动缩放）
            if base_scale_ratio > 1.0 and self.scale_factor == 1.0:
                base_scale_ratio = 1.0
            
            # 应用用户缩放因子
            final_scale_ratio = base_scale_ratio * self.scale_factor
            
        # 缩放图片
        scaled_pixmap = pixmap.scaled(
            int(img_width * final_scale_ratio),
            int(img_height * final_scale_ratio),
            Qt.AspectRatioMode.KeepAspectRatio,
            Qt.TransformationMode.SmoothTransformation
        )
        
        # 设置图片
        self.image_label.setPixmap(scaled_pixmap)
    
    def prev_image(self):
        """显示上一张图片"""
        if self.current_index > 0:
            self.current_index -= 1
            self.load_current_image()
    
    def next_image(self):
        """显示下一张图片"""
        if self.current_index < len(self.image_files) - 1:
            self.current_index += 1
            self.load_current_image()
    
    def mousePressEvent(self, event):
        """处理鼠标点击事件"""
        # 获取窗口宽度
        width = self.width()
        
        # 获取鼠标点击位置
        x = event.position().x()
        
        # 定义中间区域的宽度（窗口宽度的30%）
        middle_width = width * 0.3
        left_boundary = (width - middle_width) / 2
        right_boundary = left_boundary + middle_width
        
        # 如果点击在左侧区域，显示上一页
        if x < left_boundary:
            self.prev_image()
        # 如果点击在右侧区域，显示下一页
        elif x > right_boundary:
            self.next_image()
        # 点击中间区域不做任何操作
        else:
            pass  # 中间区域不翻页
    
    def resizeEvent(self, event):
        """处理窗口大小变化事件"""
        super().resizeEvent(event)
        
        # 窗口大小变化时重新显示当前图片以适应新大小
        if hasattr(self, 'original_pixmap') and self.original_pixmap:
            self.display_image(self.original_pixmap)
    
    def keyPressEvent(self, event):
        """处理键盘事件"""
        if event.key() == Qt.Key.Key_Left:
            self.prev_image()
        elif event.key() == Qt.Key.Key_Right:
            self.next_image()
        elif event.key() == Qt.Key.Key_Up:
            self.zoom_in_keyboard()
        elif event.key() == Qt.Key.Key_Down:
            self.zoom_out_keyboard()
        elif event.key() == Qt.Key.Key_Return or event.key() == Qt.Key.Key_Enter:
            self.toggle_fullscreen()
        elif event.key() == Qt.Key.Key_Escape:
            if self.is_fullscreen:
                self.exit_fullscreen()
            else:
                self.close()
        else:
            super().keyPressEvent(event)
    
    def zoom_in_keyboard(self):
        """键盘放大图片（上方向键）"""
        # 在适应屏幕模式下禁用键盘缩放
        if self.fit_to_screen:
            return
            
        # 每次放大10%
        self.scale_factor *= 1.1
        
        # 限制最大缩放比例
        self.scale_factor = min(5.0, self.scale_factor)
        
        # 重新显示当前图片
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏显示缩放比例
        zoom_percentage = int(self.scale_factor * 100)
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        self.statusBar().showMessage(f"正在查看: {file_name} - 缩放: {zoom_percentage}%")
    
    def zoom_out_keyboard(self):
        """键盘缩小图片（下方向键）"""
        # 在适应屏幕模式下禁用键盘缩放
        if self.fit_to_screen:
            return
            
        # 每次缩小10%
        self.scale_factor *= 0.9
        
        # 限制最小缩放比例
        self.scale_factor = max(0.1, self.scale_factor)
        
        # 重新显示当前图片
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏显示缩放比例
        zoom_percentage = int(self.scale_factor * 100)
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        self.statusBar().showMessage(f"正在查看: {file_name} - 缩放: {zoom_percentage}%")
    
    def wheelEvent(self, event):
        """处理鼠标滚轮事件进行缩放"""
        # 在适应屏幕模式下禁用滚轮缩放
        if self.fit_to_screen:
            return
            
        # 获取滚轮滚动的角度
        angle_delta = event.angleDelta().y()
        
        # 计算缩放因子
        zoom_in_factor = 1.25
        zoom_out_factor = 1 / zoom_in_factor
        
        if angle_delta > 0:
            # 向上滚动，放大
            self.scale_factor *= zoom_in_factor
        else:
            # 向下滚动，缩小
            self.scale_factor *= zoom_out_factor
        
        # 限制缩放范围
        self.scale_factor = max(0.1, min(5.0, self.scale_factor))
        
        # 重新显示当前图片
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
        
        # 更新状态栏显示缩放比例
        zoom_percentage = int(self.scale_factor * 100)
        current_image = self.image_files[self.current_index]
        file_name = current_image.split('/')[-1] if '/' in current_image else current_image
        self.statusBar().showMessage(f"正在查看: {file_name} - 缩放: {zoom_percentage}%")
    
    def toggle_fullscreen(self):
        """切换全屏模式"""
        if self.is_fullscreen:
            self.exit_fullscreen()
        else:
            self.enter_fullscreen()
        
        # 更新菜单项状态
        self.fullscreen_action.setChecked(self.is_fullscreen)
    
    def enter_fullscreen(self):
        """进入全屏模式"""
        self.is_fullscreen = True
        self.showFullScreen()
        
        # 隐藏控制栏和状态栏
        self.control_widget.hide()
        self.statusBar().hide()
        
        # 更新图片显示以适应全屏
        if self.original_pixmap:
            self.display_image(self.original_pixmap)
    
    def exit_fullscreen(self):
        """退出全屏模式"""
        self.is_fullscreen = False
        self.showNormal()
        
        # 显示控制栏和状态栏
        self.control_widget.show()
        self.statusBar().show()
        
        # 更新图片显示以适应窗口模式
        if self.original_pixmap:
            self.display_image(self.original_pixmap)